﻿using System;
using System.Linq.Expressions;
using System.Web;
using Mvc.XForms.Controls.Settings;
using Mvc.XForms.Utilities;
using System.ComponentModel;

namespace Mvc.XForms.Controls {
	public class Input<TContext> : CoreControlBase<TContext>, IInput<TContext> {
		private readonly Expression<Func<TContext, object>> bind;
		
		public InputSettings Settings { get; private set; }
		public string EncodedValue { get; set; }
		public InputType InputType { get; set; }

		public override XFormControlType ControlType {
			get { return XFormControlType.Input; }
		}

		public Input(IContainerControl<TContext> parent, InputType inputType, Expression<Func<TContext, object>> bind)
			: base(parent, bind.Body) {
			this.bind = bind;

			Settings = new InputSettings(this);
			InputType = inputType;
		}

		protected override Func<object> SetValueAction {
			get { return () => bind.Compile()(Parent.ModelContext); }
		}

		public override string Render() {
			EncodedValue = Value == null ? string.Empty : HttpUtility.HtmlEncode(Value.ToString());

			switch (InputType) {
				case InputType.Hidden:
					return RenderHidden();
				case InputType.Secret:
					return RenderSecret();
				case InputType.Upload:
					return RenderUpload();
				default:
					return RenderInput();
			}
		}

		public virtual string RenderUpload() {
			CssClass.Add("upload");
			var control = XForm.Formatter.Upload(this);
			return control;
		}

		public virtual string RenderHidden() {
			CssClass.Add("hidden");

			var control = XForm.Formatter.Hidden(this);
			return control;
		}

		public virtual string RenderSecret() {
			CssClass.Add("secret");

			var control = XForm.Formatter.Secret(this);
			return control;
		}

		public virtual string RenderInput() {
			var bindType = bind.Body.ExtractType();
			if (bindType.IsGenericType && bindType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
				bindType = new NullableConverter(bindType).UnderlyingType;

			if (bindType == typeof(bool))
				return RenderInputBoolean();
			if (bindType == typeof(DateTime))
				return RenderInputDate();
			

			CssClass.Add("input text");

			var control = XForm.Formatter.InputText(this);
			return control;
		}

		public virtual string RenderInputDate() {
			CssClass.Add("input date");

			var control = XForm.Formatter.InputDate(this);
			return control;
		}

		public virtual string RenderInputBoolean() {
			CssClass.Add("input boolean");

			var control = XForm.Formatter.InputBoolean(this);
			return control;
		}
	}
}